import EventDefines from "../Constants/EventDefines";

/**
 * joyStick
 * created by Five on 2018-12-4 17:24:29
 */

const { ccclass, property } = cc._decorator;

@ccclass
export default class Joystick extends cc.Component {
    @property(cc.Integer)
    anglePreDirQuadrant: number = 23;//每个象限的大小

    @property(cc.Node)
    fixedPoint: cc.Node = null;

    @property(cc.Node)
    movePoint: cc.Node = null;

    @property(cc.Node)
    backPic: cc.Node = null;

    @property(Number)
    movePointMoveRadius: number = 100;

    private touchID: number;//触摸事件ID（多点触控）
    private touchArea: cc.Vec2;//触摸区域大小

    private fixedPointMoveCenterPos: cc.Vec2;//固定点移动中心
    private fixedPointMoveRadius: number;//固定点移动半径
    private movePointMoveCenterPos: cc.Vec2;//移动点移动中心

    private joystickInputDir: cc.Vec2;

    onLoad() {
        let nodeSize = this.node.getContentSize()
        this.touchArea = new cc.Vec2(nodeSize.width, nodeSize.height)

        //固定点位置范围
        //@ts-ignore
        this.fixedPointMoveCenterPos = this.touchArea.div(2);
        this.fixedPointMoveRadius = this.touchArea.x / 2 - this.movePointMoveRadius;

        let self = this;
        this.node.on(cc.Node.EventType.TOUCH_START, function (event: cc.Event.EventTouch) {
            if (self.touchID == -1) {
                //触摸位置
                let touchStartPos = event.getLocation()
                self.backPic.active = true;
                self.movePoint.active = true;
                self.setBackPicPos(touchStartPos);

                //控制位置
                let pos = self.clampPos(touchStartPos, self.fixedPointMoveCenterPos, self.fixedPointMoveRadius)
                self.movePointMoveCenterPos = pos;
                //设置固定点位置
                self.setFixedPointPos(pos);
                self.setMovePointPos(pos);
                self.setBackPicPos(pos);
                self.startMoveSchedule();
                self.touchID = event.getID()
            }
        }, this);

        this.node.on(cc.Node.EventType.TOUCH_MOVE, function (event: cc.Event.EventTouch) {
            if (self.touchID == event.getID()) {
                //触摸位置
                let nowPos = event.getLocation()

                //控制位置
                let pos = self.clampPos(nowPos, self.movePointMoveCenterPos, self.movePointMoveRadius)
                //设置固定点位置
                self.setMovePointPos(pos);
            }
        }, this);

        this.node.on(cc.Node.EventType.TOUCH_END, function (event) {
            self.init()
        }, this);

        this.node.on(cc.Node.EventType.TOUCH_CANCEL, function (event) {
            self.init()
        }, this);

        this.init()
    }

    moveSchedule() {
        let angle = this.getAngleByVec2(this.getInputDir());
        this.disPatchEvent(angle);
    }

    disPatchEvent(angle) {
        var event = new cc.Event.EventCustom(EventDefines.EVENT_JOYSTICK, true);
        event.setUserData(angle);
        this.node.dispatchEvent(event);
    }

    /**
     * 初始化
     */
    init() {
        this.touchID = -1;
        this.joystickInputDir = new cc.Vec2();
        this.backPic.active = false;
        this.movePoint.active = false;

        this.setFixedPointPos(this.fixedPointMoveCenterPos);
        this.setMovePointPos(this.fixedPointMoveCenterPos);
        this.setBackPicPos(this.fixedPointMoveCenterPos);
        this.unschedule(this.moveSchedule);
        this.disPatchEvent(null);
    }

    /**
     * 开始监听移动
     */
    private startMoveSchedule() {
        this.schedule(this.moveSchedule, 0.1);
    }

    public setBackPicPos(pos: cc.Vec2) {
        this.backPic.setPosition(pos);
    }

    /**
     * 设置固定点位置
     */
    public setFixedPointPos(pos: cc.Vec2) {
        this.fixedPoint.setPosition(pos)
    }

    /**
     * 获取固定点位置
     */
    public getFixedPointPos() {
        return this.fixedPoint.getPosition()
    }

    /**
     * 设置移动点位置
     */
    public setMovePointPos(pos: cc.Vec2) {
        this.movePoint.setPosition(pos)
    }

    /**
     * 获取移动点位置
     */
    public getMovePointPos() {
        return this.movePoint.getPosition()
    }

    /**
     * 圆形限制，防止溢出
     * @param pos 需要固定位置
     * @param centerPos 限制中心位置
     * @param radius 限制半径
     */
    public clampPos(pos: cc.Vec2, centerPos: cc.Vec2, radius: number): cc.Vec2 {
        let dpos = pos.sub(centerPos)
        if (dpos.mag() > radius * 1.2) {
            return dpos.normalize().mul(radius).add(centerPos)
        } else {
            return pos;
        }
    }

    /**
     * 获取摇杆输入方向
     */
    public getInputDir(): cc.Vec2 {
        let dir = this.movePoint.getPosition().sub(this.fixedPoint.getPosition())
        if (dir.mag() > 0) {
            dir.normalizeSelf()
        }
        return dir;
    }

    /**
     * 获取摇杆象限输入方向（轴）
     */
    public getInputQuadrantDir(): cc.Vec2 {
        return this.getVec2ByQuadrant(this.getDirQuadrant(this.getInputDir()))
    }

    /**
     * 获取方向所在象限
     * @param vec 方向
     */
    public getDirQuadrant(vec: cc.Vec2): number {
        let dirQuadrant: number = null;


        if (vec.mag() > 0) {
            //非零向量
            if (vec.x > 0 && vec.y > 0)
                dirQuadrant = 1;
            else if (vec.x < 0 && vec.y > 0)
                dirQuadrant = 2;
            else if (vec.x < 0 && vec.y < 0)
                dirQuadrant = 3;
            else if (vec.x > 0 && vec.y < 0)
                dirQuadrant = 4;
            // dirQuadrant = Math.floor(this.getAngleByVec2(vec) / this.anglePreDirQuadrant)
        }


        //cc.log(this.getAngleByVec2(vec),dirQuadrant)
        return dirQuadrant;
    }

    /**
     * 二维方向获取角度
     * @param vec 方向
     */
    public getAngleByVec2(vec: cc.Vec2): number {
        let atan2 = Math.atan2(vec.y, vec.x);
        if (atan2 < 0)
            return 360 - (-atan2 * 60);
        return atan2 * 60;
    }

    /**
     * 角度获取二位方向
     * @param angle 
     */
    public getVec2ByAngle(angle: number): cc.Vec2 {
        let dir: cc.Vec2 = new cc.Vec2()
        let rad: number = (this.anglePreDirQuadrant / 2 - angle) * (Math.PI / 180)//this.anglePreDirQuadrant/2 用于旋转坐标系
        dir.x = Math.cos(rad)
        dir.y = Math.sin(rad)
        return dir.normalizeSelf()
    }

    /**
     * 根据方向象限获取角度
     * @param dirQuadrant 
     */
    public getVec2ByQuadrant(dirQuadrant: number): cc.Vec2 {
        if (dirQuadrant != null) {
            let angle: number = dirQuadrant * this.anglePreDirQuadrant;
            //获取象限的中心轴向
            angle += this.anglePreDirQuadrant / 2;


            return this.getVec2ByAngle(angle)
        } else {
            return cc.Vec2.ZERO;
        }
    }
}
